

#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "Flash.h"
#include "Bsp.h"
#include "BooterConfig.h"
#include "BooterFlag.h"
#include "BootBsp.h"
#include "SoftCrc.h"
#include "RC4Decode.h"
#include "Booter.h"
#include "Transfer.h"


static const uint8_t bootRootKey[64] = 
	"S9YrBwZZ3qKA$N*uu2il6qM3^voYK8Co$WJ2XRwYI5ldnR1Jf8117EAxi00jQA2f";

static uint8_t randKey[16];
static uint32_t currentAddress;
static uint8_t bootBuffer[2048 + 64];

#pragma pack(1)

struct {
	uint32_t appAddr;
	uint32_t appSize;
	uint16_t maxPack;
	uint8_t version;
	uint8_t state;
}bootInfo;

struct FirmwareInfo{
	uint32_t address;
	uint32_t size;
	uint32_t crc;
}firmwareInfo;

#pragma pack()


static uint32_t Booter_UpgradeEnter(void)
{
	uint32_t ErrorCode = 0;

	if (Booter_ClearAppCompeletFlag()) {
		return 1;
	}

	ErrorCode = Flash_EraseAppArea();
	return ErrorCode;
}


static void Booter_InfoInit(void){
	FlashArea_T* app = Flash_GetAppArea();

	bootInfo.state = 0;
	bootInfo.maxPack = 1024;
	bootInfo.appAddr = app->Address;
	bootInfo.appSize = app->Size;
	bootInfo.version = 0x10;	//V1.0
}

void Booter_UpgradeInit(void)
{
	Booter_InfoInit();
	Transfer_Init();
	BSP_UpgrageInit();
}

//初始化随机数生成器
static void Booter_InitRand(void){
	srand(Bsp_GetSeed());
}

//生成一组随机数
static void Booter_Rand(uint8_t r[], uint8_t len){
	int i;

	for(i = 0; i < len; i++){
		r[i] = rand();
	}
}


enum {
	CMD_Poll = 1,
	CMD_Auth1 = 2,
	CMD_Auth2 = 3,
	CMD_Setup = 4,
	CMD_Addr = 5,
	CMD_Write = 6,
	CMD_Done = 7,
	CMD_Verify = 8,
	CMD_Boot = 9,
};

//轮询设备信息
static int Booter_Poll(Block* cblk, Block* rblk){
	memcpy(rblk->buf, &bootInfo, sizeof(bootInfo));
	rblk->len += sizeof(bootInfo);
	return 0;
}

//升级认证阶段1
static int Booter_Auth1(Block* cblk, Block* rblk){
	if(cblk->len != 8){
		return 1;
	}
	RC4_Decode(bootRootKey, sizeof(bootRootKey), cblk->buf, cblk->len, randKey);
	Booter_InitRand();
	Booter_Rand(randKey + 8, 8);

	memcpy(rblk->buf, randKey + 1, 7);
	rblk->buf[7] = randKey[0];
	memcpy(rblk->buf + 8, randKey + 8, 8);
	rblk->len = 16;
	RC4_Decode(bootRootKey, sizeof(bootRootKey), rblk->buf, rblk->len, rblk->buf);
	return 0;
}
//升级认证阶段2
static int Booter_Auth2(Block* cblk, Block* rblk){
	uint8_t tbuf1[8];
	uint8_t tbuf2[8];
	
	if(cblk->len != 8){
		return 1;
	}
	memcpy(tbuf1, randKey + 9, 7);
	tbuf1[7] = randKey[8];
	RC4_Decode(bootRootKey, sizeof(bootRootKey), cblk->buf, cblk->len, tbuf2);
	if(memcmp(tbuf1, tbuf2, sizeof(tbuf1)) != 0){
		return 2;
	}
	bootInfo.state = 1;
	return 0;
}

//设置固件信息
static int Booter_Setup(Block* cblk, Block* rblk){
	struct FirmwareInfo info;
	
	if(bootInfo.state < 1){
		return 3;
	}
	
	if(cblk->len != sizeof(info)){
		return 1;
	}
	FlashArea_T* app = Flash_GetAppArea();
	memcpy(&info, cblk->buf, cblk->len);
	if(info.address < app->Address){
		return 2;
	}
	if((info.address + info.size) > (app->Address + app->Size)){
		return 4;
	}
	uint32_t pagemask = FMC_PAGE_SIZE - 1;
	uint32_t address = info.address & ~pagemask;
	uint32_t npage = info.size/FMC_PAGE_SIZE;
	if(info.size & ~pagemask){
		npage++;
	}
	Flash_ErasePages(address, npage);
	firmwareInfo = info;
	return 0;
}
//设置当前写入地址
static int Booter_Address(Block* cblk, Block* rblk){
	if(bootInfo.state < 1){
		return 3;
	}
	if(cblk->len != 4){
		return 1;
	}
	uint32_t address;
	memcpy(&address, cblk->buf, cblk->len);
	if(!(firmwareInfo.address <= address 
		&& address < firmwareInfo.address + firmwareInfo.size)){
		return 2;
	}
	currentAddress = address;
	bootInfo.state = 2;
	return 0;
}

static int Booter_Write(Block* cblk, Block* rblk){
	if(bootInfo.state < 2){
		return 3;
	}
	
	RC4_Decode(randKey, sizeof(randKey), cblk->buf, cblk->len, cblk->buf);
	
	if(currentAddress == firmwareInfo.address){
		//把起始4字节作为烧录完成标识，先缓存，待烧录完成后，再写入Flash
		uint32_t flag;
		uint8_t *buf = cblk->buf;
		memcpy(&flag, buf, sizeof(flag));
		Flash_WriteAppCompeletFlag(flag);
		memset(buf, 0xFF, sizeof(flag));
	}
	
	int ret = Flash_WirteData(currentAddress, cblk->buf, cblk->len);
	if(ret){
		return ret;
	}
	currentAddress += cblk->len;
	return 0;
}

static int Booter_Compelet(Block* cblk, Block* rblk){	
	int ret;
	if(bootInfo.state < 2){
		return 3;
	}
	ret = Flash_Sync();
	if(ret){
		return ret;
	}
	return Flash_SyncAppCompeletFlag();
}


static int Booter_Verify(Block* cblk, Block* rblk){
	uint32_t crc = crc16((const uint8_t *) firmwareInfo.address, firmwareInfo.size);
	if(crc != firmwareInfo.crc){
		return 1;
	}
	return 0;
}

static int Booter_Boot(Block* cblk, Block* rblk){
	return 0;
}

int Booter_ProcessCommand(Pack_T * cmd, Pack_T* resp)
{
	int ret = 0;
	uint8_t cc = cmd->data[0];
	Block cblk = {cmd->len - 1, cmd->data + 1};
	Block rblk = {0, resp->data + 1};
	
	resp->len = 1;

	switch(cc){
	case CMD_Poll:{
		/* 轮询指令，返回版本，最大单次传输，状态，APP地址。		*/
		ret = Booter_Poll(&cblk, &rblk);
	}
	break;
	case CMD_Auth1:{
		/* 接收上位机随机数Ra，并返回变换后的Ra1和生成的随机数Rb。	*/
		ret = Booter_Auth1(&cblk, &rblk);
	}
	break;
	case CMD_Auth2:{
		/* 接收上位机回变换后的Rb1，并校验	*/
		ret = Booter_Auth2(&cblk, &rblk);
	}
	break;
	case CMD_Setup:{
		/*下发固件信息：起始地址，大小，校验*/
		ret = Booter_Setup(&cblk, &rblk);
	}
	break;
	case CMD_Addr:{
		/*调整写入地址*/
		ret = Booter_Address(&cblk, &rblk);
	}
	break;
	case CMD_Write:{
		/*写固件*/	
		ret = Booter_Write(&cblk, &rblk);
	}
	break;
	case CMD_Done:{
		/*固件写入完成*/
		ret = Booter_Compelet(&cblk, &rblk);
	}
	break;
	case CMD_Verify:{
		/*校验烧录的固件*/
		ret = Booter_Verify(&cblk, &rblk);
	}
	break;
	case CMD_Boot:{
		/*引导*/
		resp->data[0] = Booter_Boot(&cblk, &rblk);
		return 1;
	}
	break;
	default :{
		ret = -1;
	}
	break;
	}
	resp->data[0] = ret;
	if(ret == 0){
		resp->len += rblk.len;
	}
	return 0;
}



void Booter_Upgrading(uint32_t mode)
{
	int ret;
	uint32_t wait = 6000;
	Pack_T* rpack = (Pack_T*) bootBuffer;
	Pack_T* cpack;
	int count = 0;
	//等待连接
	ret = Transfer_WaitConnect(2000);
	if(ret >= 0){
		//设备已连接，接收命令
		ret = Transfer_InPack(&cpack, wait);
	}

	if (ret < 0) {
		//等待超时
		if(mode == MODE_BOOT){
			//引导模式，退出，引导APP
			return;
		}
	}

	while (1) {
		if(ret == 0){
			//处理升级指令
			ret = Booter_ProcessCommand(cpack, rpack);
			//返回处理结果
			Transfer_OutPack(rpack);
			
			if (ret) {
				break;
			}
		}
		//接收下一条指令
		ret = Transfer_InPack(&cpack, 12 * 1000);
		BSP_RunState(++count & 1);
	}
}




















































